// package 自定义命令行
package ocmd

import (
	"bufio"
	"fmt"
	"io"
	"osiris/logger"
	"strings"
	"sync"
)

// const 命令关键字
const (
	//一级
	EXIT = "exit"
	HELP = "help"
	PING = "ping"

	//peers 一级
	PEERS = "peers"
	//peers 二级
	ADDR   = "addr"
	PUBKEY = "pubkey"

	//txpool 一级
	TXPOOL = "txpool"
	//txpool 二级
	LOCAL  = "local"
	REMOTE = "remote"
	//txpool 三级
	QUEUED  = "queued"
	PENDING = "pending"

	//bootstrap 一级
	BOOTSTRAP = "bootstrap"

	//autotx 一级
	AUTOTX = "autotx"
	//autotx 二级
	START = "start"
	STOP  = "stop"

	//rm 一级
	RM = "rm"
	//rm 二级
	STATE = "state"

	//pos
	POS = "pos"
)

// CommandHandler 命令
type CommandHandler interface {

	// Handle 具体的执行逻辑
	//  @param inputs 参数输入
	//  @param wg 等待命令执行完毕的wg（命令执行完毕后需wg.Done())(Handle方法return前必须要wg.Done(),或者将wg传到别的协程里进行wg.Done())
	//  @return error 发生的错误
	Handle(inputs []string, wg *sync.WaitGroup) error

	// PrintHelp 打印帮助信息, 在错误发生时会调用
	PrintHelp()
}

// ReadCommand 循环读命令
//
//	@param stdReader
func ReadCommand(stdReader *bufio.Reader) {
	wg := new(sync.WaitGroup)
	defer func() {
		logger.EnableStdLog()
	}()

	for {
		//读命令期间允许在终端打印日志
		logger.DisableStdLog()
		fmt.Print(">> ")
		input, err := stdReader.ReadString('\n')
		if err != nil {
			logger.EnableStdLog()

			if err == io.EOF {
				return
			}

			logger.Error(map[string]interface{}{"[ocmd] [Run command] read string": err})
			logger.Printf("Raed Command Error due to %s\n", err.Error())
			return
		}

		inputs := strings.Fields(input)
		if len(inputs) == 0 {
			continue
		}

		//确认本轮命令执行完后再进行下一轮
		wg.Add(1)
		//执行命令期间允许在终端打印日志
		logger.EnableStdLog()
		exit := handleCommand(inputs, wg)
		if exit {
			fmt.Println("Bye!")
			return
		}
		wg.Wait()
	}
}

// buildCommandHandler 根据命令输入构造对应的handler
//
//	@param inputs
//	@return CommandHandler
func buildCommandHandler(inputs []string) CommandHandler {
	switch inputs[0] {
	case PING:
		return &PingHandler{}

	case PEERS:
		return &PeersHandler{}

	case TXPOOL:
		return &TxPoolHandler{}

	case BOOTSTRAP:
		return &BootstrapHandler{}

	case AUTOTX:
		return &AutoTxHandler{}

	case RM:
		return &RmHandler{}

	case POS:
		return &PosHandler{}

	default:
		return nil
	}
}

// handleCommand 处理输入的命令
//
//	@param inputs 输入
//	@param wg 命令执行完毕的信号
//	@return bool 是否需要退出命令行
func handleCommand(inputs []string, wg *sync.WaitGroup) bool {
	//别特么忘了找个地方wg.Done（）
	if inputs[0] == HELP {
		PrintCommands()
		wg.Done()
		return false
	}

	if inputs[0] == EXIT {
		logger.Println("Bye")
		wg.Done()
		return true
	}

	handler := buildCommandHandler(inputs)
	if handler == nil {
		PrintCommands()
		wg.Done()
		return false
	}

	err := handler.Handle(inputs, wg)
	if err != nil {
		logger.Println(err.Error())
		handler.PrintHelp()
	}

	return false
}

func PrintCommands() {
	fmt.Println("The Commands are:")
	printCommand(PING, "say hello to another node")
	printCommand(PEERS, "show information of peer stored in the Ha.PeerStore")
	printCommand(TXPOOL, "show information of txpool")
	printCommand(BOOTSTRAP, "get peers nearby by bootstrap")
	printCommand(AUTOTX, "use virtual client to do tx, only for test")
	printCommand(RM, "delete stored information")
	printCommand(POS, "start pos consensus")
	printCommand(EXIT, "exit command mode")
}

func printCommand(command string, description string) {
	fmt.Printf("    %s    %s\n", command, description)
}
